package rov.ui;

import rov.ui.view.*;
import rov.data.LogManager;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;


// manages all windows for the application
public class WindowManager
{
    private static final Class[] sViews = new Class[]
        {
            ControlsView.class, SensorsView.class,
            ModelView.class,  TasksView.class, PreferencesView.class
        };
    private static final Object mLock = new Object();
    private static volatile WindowManager sInstance;


    // returns the application-wide singleton
    public static WindowManager getInstance()
    {
        if (sInstance == null)
        {
            synchronized (mLock)
            {
                if (sInstance == null)
                    sInstance = new WindowManager();
            }
        }

        return sInstance;
    }


    private Hashtable<Container,JInternalFrame> mWindows;
    private JFrame mFrame;
    private JDesktopPane mDesktop;
    private JMenuBar mMenu;
    private JMenu mViewMenu;
    private int mX;
    private int mY;
    private int mMaxHeight;


    // get the singleton through the getInstance method
    private WindowManager()
    {
        mWindows = new Hashtable<Container,JInternalFrame>();
        mFrame = new JFrame("UNH Wildcats ROV Controller");
        mDesktop = new JDesktopPane();
        mMenu = new JMenuBar();
        mViewMenu = new JMenu("View");
        mMenu.add(mViewMenu);

        mFrame.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                LogManager.getShared().closeAll();
            }
        });

        // add menu item for opening all views simultaneously
        JMenuItem all = createViewItem("All", new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                for (Class view : sViews)
                {
                    IView v = instanceView(view);

                    if (v != null)
                        v.create();
                }
            }
        });

        // add menu item for each view
        for (final Class view : sViews)
        {
            IView v = instanceView(view);

            if (v != null)
            {
                ActionListener al = new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
                    {
                        IView v = instanceView(view);

                        if (v != null)
                            v.create();
                    }
                };

                createViewItem(v.getTitle(), al);
            }
        }

        mFrame.setJMenuBar(mMenu);
        mFrame.add(mDesktop);
        mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mFrame.setSize(800, 950);
    }


    public void setVisible(boolean visible)
    {
        mFrame.setVisible(true);
    }


    // returns an instance of view or null if there was an error
    private IView instanceView(Class view)
    {
        IView v = null;

        try
        {
            Object viewObj = view.newInstance();

            if (viewObj instanceof IView)
                v = (IView) viewObj;
            else
                System.err.println("Error: View \"" + view.getName() +
                                   "\" does not implement IView");
        }
        catch (InstantiationException e)
        {
            System.err.println("Error instantiating \"" + view.getName() + "\", " + e);
        }
        catch (IllegalAccessException e)
        {
            System.err.println("Error instantiating \"" + view.getName() + "\", " + e);
        }

        return v;
    }


    // creates a menu item, adds it to the "View" menu in the frame's menubar
    public JMenuItem createViewItem(String title, ActionListener al)
    {
        JMenuItem item = new JMenuItem(title);
        item.addActionListener(al);
        mViewMenu.add(item);
        return item;
    }


    // creates a window, returns the root pane of the new window
    public Container createWindow(String title,
                                  boolean resizable, boolean closable,
                                  boolean maximizable, boolean iconifiable,
                                  int width, int height)
    {
        final JInternalFrame frame = new JInternalFrame(title, resizable,
                                            closable, maximizable, iconifiable);

        frame.addComponentListener(new ComponentAdapter()
        {
            public void componentMoved(ComponentEvent e)
            {
                frame.repaint();
            }
        });

        if ((mX+width) > mFrame.getWidth())
        {
            mX = 0;
            mY += mMaxHeight;
            mMaxHeight = height;
        }

        frame.reshape(mX, mY, width, height);
        mDesktop.add(frame);

        if (height > mMaxHeight)
            mMaxHeight = height;

        mX += width;

        Container cp = frame.getContentPane();
        mWindows.put(cp, frame);

        frame.setVisible(true);
        return cp;
    }


    // destroys a window
    // c must have been returned by a previous call to createWindow
    public void destroyWindow(Container cp)
    {
        JInternalFrame frame = mWindows.remove(cp);
        mDesktop.remove(frame);
    }
}
